#include "sdk.h"
#include <wx/confbase.h>
#include <wx/fileconf.h>
#include <wx/intl.h>
#include <wx/string.h>
#include "workspaceloader.h"
#include "manager.h"
#include "configmanager.h"
#include "projectmanager.h"
#include "logmanager.h"
#include "globals.h"
#include "editormanager.h"
#include "M_Code_auibook.h"
#include <tinyxml.h>
#include "tinywxuni.h"
#include <wx/intl.h>

WorkspaceLoader::WorkspaceLoader() {
}

WorkspaceLoader::~WorkspaceLoader() {
}

inline ProjectManager* GetpMan() {
  return Manager::Get()->GetProjectManager();
}
inline LogManager* GetpMsg() {
  return Manager::Get()->GetLogManager();
}


bool WorkspaceLoader::Open( const wxString& filename, wxString& Title ) {
  TiXmlDocument doc;
  if( !TinyXML::LoadDocument( filename, &doc ) ) {
    return false;
  }
  if( !GetpMan() || !GetpMsg() ) {
    return false;
  }
  TiXmlElement* root = doc.FirstChildElement( "m_Code_workspace_file" );
  if( !root ) {
    GetpMsg()->Log( _T( "Not a valid Code::Blocks workspace file..." ) );
    return false;
  }
  TiXmlElement* wksp = root->FirstChildElement( "Workspace" );
  if( !wksp ) {
    GetpMsg()->Log( _T( "No 'Workspace' element in file..." ) );
    return false;
  }
  Title = cbC2U( wksp->Attribute( "title" ) );
  TiXmlElement* proj = wksp->FirstChildElement( "Project" );
  if( !proj ) {
    GetpMsg()->DebugLog( _T( "Workspace file contains no projects..." ) );
    return false;
  }
  while( proj ) {
    if( Manager::IsAppShuttingDown() || !GetpMan() || !GetpMsg() ) {
      return false;
    }
    wxString projectFilename = UnixFilename( cbC2U( proj->Attribute( "filename" ) ) );
    if( projectFilename.IsEmpty() ) {
      GetpMsg()->DebugLog( _T( "'Project' node exists, but no filename?!?" ) );
    } else {
      wxFileName fname( projectFilename );
      wxFileName wfname( filename );
      fname.MakeAbsolute( wfname.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR ) );
      M_Code_Project* pProject = GetpMan()->LoadProject( fname.GetFullPath(), false );
      if( !pProject ) {
        msging( _T( "Unable to open " ) + projectFilename,
                _T( "Opening WorkSpace" ) + filename, wxICON_WARNING );
      }
    }
    proj = proj->NextSiblingElement( "Project" );
  }
  proj = wksp->FirstChildElement( "Project" );
  while( proj ) {
    M_Code_Project* thisprj = nullptr;
    wxString projectFilename = UnixFilename( cbC2U( proj->Attribute( "filename" ) ) );
    if( projectFilename.IsEmpty() ) {
      GetpMsg()->Log( _T( "'Project' node exists, but no filename?!?" ) );
      thisprj = nullptr;
    } else {
      wxFileName fname( projectFilename );
      wxFileName wfname( filename );
      fname.MakeAbsolute( wfname.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR ) );
      thisprj = Manager::Get()->GetProjectManager()->IsOpen( fname.GetFullPath() );
    }
    if( thisprj ) {
      TiXmlElement* dep = proj->FirstChildElement( "Depends" );
      while( dep ) {
        wxFileName fname( UnixFilename( cbC2U( dep->Attribute( "filename" ) ) ) );
        wxFileName wfname( filename );
        fname.MakeAbsolute( wfname.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR ) );
        M_Code_Project* depprj = Manager::Get()->GetProjectManager()->IsOpen( fname.GetFullPath() );
        if( depprj ) {
          Manager::Get()->GetProjectManager()->AddProjectDependency( thisprj, depprj );
        }
        dep = dep->NextSiblingElement( "Depends" );
      }
    }
    proj = proj->NextSiblingElement( "Project" );
  }
  return true;
}

bool WorkspaceLoader::Save( const wxString& title, const wxString& filename ) {
  const char* ROOT_TAG = "m_Code_workspace_file";
  TiXmlDocument doc;
  doc.SetCondenseWhiteSpace( false );
  doc.InsertEndChild( TiXmlDeclaration( "UTF-8", "yes" ) );
  TiXmlElement* rootnode = static_cast<TiXmlElement*>( doc.InsertEndChild( TiXmlElement( ROOT_TAG ) ) );
  if( !rootnode ) {
    return false;
  }
  TiXmlElement* wksp = static_cast<TiXmlElement*>( rootnode->InsertEndChild( TiXmlElement( "Workspace" ) ) );
  wksp->SetAttribute( "title", cbU2C( title ) );
  ProjectsArray* arr = Manager::Get()->GetProjectManager()->GetProjects();
  for( unsigned int i = 0; i < arr->GetCount(); ++i ) {
    M_Code_Project* prj = arr->Item( i );
    wxFileName wfname( filename );
    wxFileName fname( prj->GetFilename() );
    fname.MakeRelativeTo( wfname.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR ) );
    TiXmlElement* node = static_cast<TiXmlElement*>( wksp->InsertEndChild( TiXmlElement( "Project" ) ) );
    node->SetAttribute( "filename", cbU2C( UnixFilename( fname.GetFullPath(), wxPATH_UNIX ) ) );
    const ProjectsArray* deps = Manager::Get()->GetProjectManager()->GetDependenciesForProject( prj );
    if( deps && deps->GetCount() ) {
      for( size_t j = 0; j < deps->GetCount(); ++j ) {
        prj = deps->Item( j );
        fname.Assign( prj->GetFilename() );
        fname.MakeRelativeTo( wfname.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR ) );
        TiXmlElement* dnode = static_cast<TiXmlElement*>( node->InsertEndChild( TiXmlElement( "Depends" ) ) );
        dnode->SetAttribute( "filename", cbU2C( UnixFilename( fname.GetFullPath(), wxPATH_UNIX ) ) );
      }
    }
  }
  return cbSaveTinyXMLDocument( &doc, filename );
}

bool WorkspaceLoader::SaveLayout( const wxString& filename ) {
  const char* ROOT_TAG = "m_Code_workspace_layout_file";
  TiXmlDocument doc;
  doc.SetCondenseWhiteSpace( false );
  doc.InsertEndChild( TiXmlDeclaration( "UTF-8", "yes" ) );
  TiXmlElement* rootnode = static_cast<TiXmlElement*>( doc.InsertEndChild( TiXmlElement( ROOT_TAG ) ) );
  if( !rootnode ) {
    return false;
  }
  ProjectManager *pm = Manager::Get()->GetProjectManager();
  if( !pm ) {
    return false;
  }
  if( const M_Code_Project *project = pm->GetActiveProject() ) {
    TiXmlElement *el =
      static_cast<TiXmlElement*>(
        rootnode->InsertEndChild( TiXmlElement( "ActiveProject" ) ) );
    wxFileName wfname( filename );
    wxFileName fname( project->GetFilename() );
    fname.MakeRelativeTo( wfname.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR ) );
    el->SetAttribute( "path", cbU2C( UnixFilename( fname.GetFullPath(), wxPATH_UNIX ) ) );
  }
  if( const M_Code_Workspace* wsp = pm->GetWorkspace() ) {
    const wxString preferredTarget = wsp->GetPreferredTarget();
    if( ! preferredTarget.IsEmpty() ) {
      TiXmlElement* el =
        static_cast<TiXmlElement*>(
          rootnode->InsertEndChild( TiXmlElement( "PreferredTarget" ) ) );
      el->SetAttribute( "name", cbU2C( preferredTarget ) );
    }
  }
  if( Manager::Get()->GetConfigManager( _T( "app" ) )->ReadBool( _T( "/environment/enable_editor_layout" ), false ) ) {
    TiXmlElement *el =
      static_cast<TiXmlElement*>(
        rootnode->InsertEndChild( TiXmlElement( "EditorTabsLayout" ) ) );
    el->SetAttribute( "layout", cbU2C( Manager::Get()->GetEditorManager()->GetNotebook()->SavePerspective() ) );
  }
  return cbSaveTinyXMLDocument( &doc, filename );
}

bool WorkspaceLoader::LoadLayout( const wxString& filename ) {
  TiXmlDocument doc;
  if( ! TinyXML::LoadDocument( filename, &doc ) ) {
    return false;
  }
  if( ! GetpMan() || ! GetpMsg() ) {
    return false;
  }
  TiXmlElement* root = doc.FirstChildElement( "m_Code_workspace_layout_file" );
  if( !root ) {
    GetpMsg()->DebugLog( _T( "无效的 workspace layout file: File is invalid." ) );
    return false;
  }
  if( TiXmlElement* el = root->FirstChildElement( "ActiveProject" ) ) {
    wxFileName fname = cbC2U( el->Attribute( "path" ) );
    wxFileName wfname( filename );
    fname.MakeAbsolute( wfname.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR ) );
    M_Code_Project *project = GetpMan()->IsOpen( fname.GetFullPath() );
    if( project ) {
      GetpMan()->SetProject( project );
      Manager::Get()->GetLogManager()->DebugLog( F( _T( "Project %s has been activated." ), fname.GetFullPath().wx_str() ) );
    } else
    { Manager::Get()->GetLogManager()->DebugLog( F( _T( "Could not activate project: %s" ), fname.GetFullPath().wx_str() ) ); }
  }
  if( TiXmlElement* el = root->FirstChildElement( "PreferredTarget" ) ) {
    const wxString name = cbC2U( el->Attribute( "name" ) );
    M_Code_Workspace *wsp = GetpMan()->GetWorkspace();
    if( wsp ) {
      wsp->SetPreferredTarget( name );
    }
  }
  if( ( Manager::Get()->GetConfigManager( _T( "app" ) )->ReadBool( _T( "/environment/enable_editor_layout" ), false ) ) ) {
    if( TiXmlElement* el = root->FirstChildElement( "EditorTabsLayout" ) ) {
      if( el->Attribute( "layout" ) ) {
        Manager::Get()->GetEditorManager()->GetNotebook()->LoadPerspective( cbC2U( el->Attribute( "layout" ) ) );
      }
    }
  }
  return true;
}
